home *** CD-ROM | disk | FTP | other *** search
/ Aminet 32 / Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso / Aminet / comm / tcp / Socks5.lha / Socks5 / src / lib / msg.c < prev    next >
C/C++ Source or Header  |  1999-03-10  |  9KB  |  292 lines

  1. /* Copyright (c) 1995-1999 NEC USA, Inc.  All rights reserved.               */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6.  
  7. /*
  8.  * $Id: msg.c,v 1.30.2.1.2.4 1999/02/03 22:35:15 steve Exp $
  9.  */
  10.  
  11. /* This file contains functions support reliable message transport under any */
  12. /* (UDP or TCP) protocol.                                                    */
  13. #include "socks5p.h"
  14. #include "buffer.h"
  15. #include "block.h"
  16. #include "msg.h"
  17. #include "log.h"
  18.  
  19. int S5IORecv(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int ioflags, int libflags, double *timerm) {
  20.     int nr, sval, rlen = size;
  21.     struct timeval sv, *svpt;
  22.     fd_set fds, b;
  23.     
  24. #ifdef STRICT_TIMEOUT
  25.     struct timeval ts, te;
  26. #endif
  27.  
  28.     if (libflags & S5_IOFLAGS_TIMED && !timerm) {
  29.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: NULL timeout pointer passed");
  30.     SETSOCKETERROR(ETIMEDOUT);
  31.     return -1;
  32.     }
  33.     
  34.     if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
  35.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Warning: Cannot reliably read n bytes and not handle restarts");
  36.     }
  37.     
  38.     /* We may have read in some stuff and buffered it.  Rather than replace  */
  39.     /* select, lets just read the stuff *out* of the buffer first...         */
  40.     while (1) {
  41.     if ((sval = S5BufCheckData(fd, info)) < 0) return -1;
  42.     if (sval == 0) break;
  43.  
  44.     if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) < 0) return -1;
  45.     if (nr == 0) return (size - rlen);
  46.  
  47.     rlen -= nr; buf += nr;
  48.     if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
  49.     if (rlen == 0) return size;
  50.     }
  51.  
  52.     /* Read again and again until we have an error, we run out of time, or   */
  53.     /* we just read all that we wanted to.  If STRICT_TIMEOUT is defined,    */
  54.     /* subtract the amount of time we've spent at each point form the time   */
  55.     /* we are allowing *total*...This is kind of expensive...An alternative, */
  56.     /* which has nearly the same consequences is is to spend that amount of  */
  57.     /* time *each* read.  If the data is too interspersed, it will die...    */
  58.     FD_ZERO(&b);
  59.     FD_SET(fd, &b);
  60.     
  61.     for (fds = b; rlen > 0; fds = b) {
  62.     if (libflags & S5_IOFLAGS_TIMED) {
  63.         sv.tv_sec  = (int)*timerm;
  64.         sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
  65.     
  66. #ifdef STRICT_TIMEOUT
  67.         if (gettimeofday(&ts, NULL) < 0) {
  68.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
  69.         SETSOCKETERROR(ETIMEDOUT);
  70.         goto interrupted;
  71.         }
  72. #endif
  73.     } else {
  74.         sv.tv_sec = 0;
  75.         sv.tv_usec = 0;
  76.     }
  77.     
  78.     if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
  79.     else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
  80.     else svpt = NULL;
  81.  
  82.     if ((sval = REAL(select)(fd + 1, &fds, NULL, NULL, svpt)) == 0) {
  83.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "S5IORecv: select failed: Timed out");
  84.         if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
  85. #if defined(sun) && !defined(__svr4__)
  86.             else SETSOCKETERROR(EWOULDBLOCK);
  87. #else
  88.             else SETSOCKETERROR(EAGAIN);
  89. #endif
  90.         sval = -1;
  91.         goto interrupted;
  92.     }
  93.     
  94. #ifdef STRICT_TIMEOUT
  95.     if (libflags & S5_IOFLAGS_TIMED) {
  96.         if (gettimeofday(&te, NULL) < 0) {
  97.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: gettimeofday failed: %m");
  98.         SETSOCKETERROR(ETIMEDOUT);
  99.             sval = -1;
  100.         goto interrupted;
  101.         }
  102.     
  103.         *timerm -= (te.tv_sec  - ts.tv_sec);
  104.         *timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
  105.         if (*timerm < 0.0) *timerm = 0.0;
  106.     }
  107. #endif
  108.     
  109.     if (sval < 0) {
  110.         if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
  111.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IORecv: Select failed: %m");
  112.         goto interrupted;
  113.     }
  114.     
  115.     while (rlen > 0) {
  116.         switch ((sval = S5BufCheckPacket(fd, info))) {
  117.         case 0:
  118.         case -1: goto interrupted;
  119.         default: break;
  120.         }
  121.  
  122.             /* packet is not available...                                    */
  123.         if (sval < 0) break;
  124.  
  125.          if ((nr = S5BufReadPacket(fd, info, buf, rlen, ioflags)) <= 0) {
  126.         sval = nr;
  127.          goto interrupted;
  128.         }
  129.  
  130.         if (!(libflags & S5_IOFLAGS_NBYTES)) return nr;
  131.  
  132.             rlen -= nr;
  133.         buf  += nr;
  134.         }
  135.  
  136.         if (sval < 0 && !(libflags & S5_IOFLAGS_NBYTES)) {
  137.         sval = -1;
  138.         goto interrupted;
  139.     }
  140.     }
  141.     
  142.     return size;
  143.  
  144. interrupted:
  145.     /* We read some data in, but we were interrupted and we aren't supposed  */
  146.     /* to restart... So we have to store what we've read so far in info...   */
  147.     if (S5BufUnreadPacket(info, buf-(size-rlen), size-rlen)) {
  148.         /* Nowhere to store what we've read... Bummer...                     */
  149.     }
  150.  
  151.     return sval;
  152. }
  153.  
  154. int S5IOSend(S5IOHandle fd, S5IOInfo *info, char *buf, int size, int flags, int libflags, double *timerm) {
  155.     struct timeval sv, *svpt;
  156.     int nw, wlen, sval;
  157.     fd_set fds, b;
  158.     
  159. #ifdef STRICT_TIMEOUT
  160.     struct timeval ts, te;
  161. #endif
  162.  
  163.     if (libflags & S5_IOFLAGS_TIMED && !timerm) {
  164.     SETSOCKETERROR(ETIMEDOUT);
  165.     return -1;
  166.     }
  167.     
  168.     if ((libflags & S5_IOFLAGS_NBYTES) && !(libflags & S5_IOFLAGS_RESTART)) {
  169.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Warning: Cannot reliably write n bytes and not handle restarts");
  170.     }
  171.     
  172.     FD_ZERO(&b);
  173.     FD_SET(fd, &b);
  174.     
  175.     for (fds = b, wlen = size; wlen > 0; fds = b) {
  176.     if (libflags & S5_IOFLAGS_TIMED) {
  177.         sv.tv_sec  = (int)*timerm;
  178.         sv.tv_usec = (int)((*timerm - (double)sv.tv_sec) * 1000000.0);
  179.         
  180. #ifdef STRICT_TIMEOUT
  181.         if (gettimeofday(&ts, NULL) < 0) {
  182.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
  183.         SETSOCKETERROR(ETIMEDOUT);
  184.         return -1;
  185.         }
  186. #endif
  187.     } else {
  188.         sv.tv_sec = 0;
  189.         sv.tv_usec = 0;
  190.     }
  191.     
  192.     if (libflags & S5_IOFLAGS_TIMED) svpt = &sv;
  193.     else if (ISNBLOCK(fd) && !(libflags & S5_IOFLAGS_NBYTES)) svpt = &sv;
  194.     else svpt = NULL;
  195.  
  196.     if ((sval = REAL(select)(fd + 1, NULL, &fds, NULL, svpt)) == 0) {
  197.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "S5IOSend: select failed: Timed out");
  198.         if (libflags & S5_IOFLAGS_TIMED) SETSOCKETERROR(ETIMEDOUT);
  199. #if defined(sun) && !defined(__svr4__)
  200.             else SETSOCKETERROR(EWOULDBLOCK);
  201. #else
  202.             else SETSOCKETERROR(EAGAIN);
  203. #endif
  204.         return -1;
  205.     }
  206.     
  207. #ifdef STRICT_TIMEOUT
  208.     if (libflags & S5_IOFLAGS_TIMED) {
  209.         if (gettimeofday(&te, NULL) < 0) {
  210.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: gettimeofday failed: %m");
  211.         SETSOCKETERROR(ETIMEDOUT);
  212.         return -1;
  213.         }
  214.         
  215.         *timerm -= (te.tv_sec  - ts.tv_sec);
  216.         *timerm -= (te.tv_usec - ts.tv_usec)/1000000.0;
  217.         if (*timerm < 0.0) *timerm = 0.0;
  218.     }
  219. #endif
  220.     
  221.     if (sval < 0) {
  222.         if (ISSOCKETERROR(EINTR) && libflags & S5_IOFLAGS_RESTART) continue;
  223.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOSend: Select failed: %m");
  224.         return -1;
  225.     }
  226.     
  227.     do {
  228.         if ((nw = S5BufWritePacket(fd, info, buf, wlen, flags)) > 0) break;
  229.             if (ISSOCKETERROR(EINTR) && !(libflags & S5_IOFLAGS_RESTART)) break;
  230.             if ((ISSOCKETERROR(EWOULDBLOCK) || ISSOCKETERROR(EAGAIN)) && !(libflags & S5_IOFLAGS_NBYTES)) break;
  231.         nw = 0;
  232.         } while (S5IOCheck(fd) >= 0);
  233.  
  234.     if (nw < 0) {
  235.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING,  0, "S5IOSend: failed: %m");
  236.         return nw;
  237.     }
  238.  
  239.     if (nw == 0) {
  240.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING,  0, "S5IOSend: peer closed");
  241.         SETSOCKETERROR(EPIPE);
  242.         return -1;
  243.     }
  244.  
  245.     if (!(libflags & S5_IOFLAGS_NBYTES)) return nw;
  246.  
  247.     wlen -= nw;
  248.     buf  += nw;
  249.     }
  250.     
  251.     return size;
  252. }
  253.  
  254. /* See what's going on with a socket -- is the connection still valid?       */
  255. int S5IOCheck(S5IOHandle fd) {
  256.     struct timeval tv = { 0, 0 };
  257.     fd_set rfds, b;
  258.     char dummy;
  259.     int sv, n;
  260.         
  261.     FD_ZERO(&b);
  262.     FD_SET(fd, &b);
  263.  
  264.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: Checking socket status");
  265.  
  266.     /* Poll the file descriptor real quick, and see what comes back...       */
  267.     while (1) {
  268.     rfds = b; 
  269.         switch ((sv = REAL(select)(fd+1, &rfds, NULL, NULL, &tv))) {
  270.         case 1:
  271.             /* Something happened -- either an error or data, ok to recv */
  272.             n = RECVSOCKET(fd, &dummy, 1, MSG_PEEK);
  273.             if (n < 0 && ISSOCKETERROR(EINTR)) continue;
  274.         else if (n <= 0) {
  275.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(1), 0, "S5IOCheck: recv failed: %m");
  276.             return -1;
  277.             }
  278.             /* fallthrough -- there is real data there...                */
  279.         case 0:
  280.             /* Nothing's happening -- no error, all's ok.                */
  281.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5IOCheck: ok");
  282.             return sv;
  283.         default:
  284.             /* Not a valid socket (?).                                   */
  285.                 if (ISSOCKETERROR(EINTR)) continue;
  286.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5IOCheck: select failed: %m");
  287.             return -1;
  288.         }
  289.     }
  290. }
  291.  
  292.